<template>
  <div
    class="c-table-edit-cell-wrapper"
    :class="[
      props.trigger === 'click-cell' && !props.disabled && !props.onlyShowValue ? 'g-cur-poi' : '',
      props.hover === 'row-hover' ? 'table-row' : 'table-cell'
    ]"
    v-loading="loading"
    v-bind="cellWrapperBind(props.trigger)"
  >
    <input
      v-if="!props.onlyShowValue && (editFlag || alwaysInput)"
      :step="0.000001"
      ref="inputRef"
      :type="inputType"
      class="c-table-edit-cell-input"
      :class="[
        activeFlag ? 'c-table-edit-cell-input--active' : '',
        props.align ? `c-table-edit-cell-input--${props.align}` : '',
        !activeFlag && props.isError ? 'c-table-edit-cell-input--error is-error' : ''
      ]"
      v-model.lazy="localValue"
      :placeholder="inputPlaceholder"
      @blur="handleRowBlur"
      @focus="handleFocus"
      @keyup.enter="handleEnterSaveInput"
      @wheel.stop.prevent
    />
    <div
      v-else
      class="g-ell c-table-edit-cell-text"
      :class="[props.align ? `c-table-edit-cell-text--${props.align}` : '']"
      v-ellTooltip="
        `${props.modelValue || props.modelValue === 0 ? props.modelValue + props.suffix : ''}`
      "
      :style="cellTextStyle"
    >
      <slot v-if="showValue">
        <span class="g-ell">{{ props.modelValue }}{{ props.suffix }}</span>
      </slot>
      <span
        v-else
        :class="props.showPlaceholderStyle ? 'c-table-edit-cell-text--placeholder' : ''"
        >{{ disabled ? '-' : props.placeholder }}</span
      >
    </div>
    <div
      class="c-table-edit-cell-icon-wrapper"
      :class="[
        props.align ? `c-table-edit-cell-icon-wrapper--${props.align}` : '',
        props.alwaysShowIcon ? '' : 'c-table-edit-cell-icon-wrapper--hide'
      ]"
      v-if="!props.onlyShowValue"
    >
      <CIcon
        v-if="!disabled"
        type="c-xian-bianji"
        class="c-table-edit-cell-icon"
        :class="[props.trigger === 'click-cell' ? '' : 'g-cur-poi']"
        @click="handleEditBtnClick"
      ></CIcon>
    </div>
  </div>
</template>
<script lang="ts" setup name="CTableEditCell">
import { watch } from 'vue';
import {
  getCurrentInstance,
  nextTick,
  ref,
  computed,
  withDefaults,
  defineProps,
  defineEmits,
  defineExpose
} from 'vue';
interface GTableEditCellProps {
  // input的type属性，默认text
  inputType?: 'text' | 'number';
  modelValue: any;
  // 只展示值
  onlyShowValue?: boolean;
  // 表格行，仅作更新时入参返回
  tableRow: any;
  // 后缀名
  suffix?: string;
  // 占位符
  placeholder?: string;
  // 是否展示占位符样式
  showPlaceholderStyle?: boolean;
  // 输入框占位符
  inputPlaceholder?: string;
  // 更新操作方法
  updateFn?: (value: string, tableRow: any) => Promise<boolean>;
  // 触发方式
  trigger?: 'click-icon' | 'click-cell';
  // localValue格式化函数
  localValueFormatter?: (value: any) => any;
  // 编辑按钮hover出现的类型
  hover?: 'row-hover' | 'cell-hover';
  disabled?: boolean;
  /**
   * 输入框对齐方式
   */
  align?: 'left' | 'right';
  /**
   * 一直显示输入框
   */
  alwaysInput?: boolean;
  /**
   * 是否显示错误状态
   */
  isError?: boolean;
  /**
   * 一直显示icon
   */
  alwaysShowIcon?: boolean;
  /**
   * 背景色
   */
  bgColor?: string;
}
const props = withDefaults(defineProps<GTableEditCellProps>(), {
  onlyShowValue: false,
  type: 'text',
  suffix: '',
  placeholder: '-',
  showPlaceholderStyle: false,
  inputPlaceholder: '请输入',
  trigger: 'click-icon',
  hover: 'row-hover',
  align: 'left',
  alwaysInput: false,
  isError: false,
  alwaysShowIcon: true
});
const emits = defineEmits(['update:modelValue', 'change', 'open', 'close']);
const inputRef = ref();
const localValue = ref();
const editFlag = ref(false);
const activeFlag = ref(false);
const loading = ref(false);
const instance = getCurrentInstance()!;
// 是否展示值
const showValue = computed(() => {
  if (props.onlyShowValue) return true;
  if (!editFlag.value) {
    if (props.modelValue) return true;
    if (typeof props.modelValue === 'number') return true;
  }
  return false;
});

const cellTextStyle = computed(() => {
  const style: any = {};
  if (props.bgColor) {
    style.backgroundColor = props.bgColor;
  }
  return style;
});

function cellWrapperBind(trigger: 'click-icon' | 'click-cell') {
  if (trigger === 'click-cell' && !props.disabled) {
    return {
      onClick: handleClickCell
    };
  } else {
    return {};
  }
}

function handleClickCell() {
  handleEditBtnClick();
}

// 点击编辑按钮
function handleEditBtnClick() {
  if (props.disabled) return;
  console.log('handleEditBtnClick');
  editFlag.value = true;
  emits('open', {
    instance,
    handleCloseInput
  });
  localValue.value = props.modelValue;
  nextTick(() => {
    inputRef.value.focus();
  });
}

watch(
  () => props.modelValue,
  val => {
    localValue.value = val;
  }
);
function handleFocus() {
  activeFlag.value = true;
}

// 输入框失去焦点操作
async function handleRowBlur() {
  console.log('handleRowBlur');
  activeFlag.value = false;
  await handleInputChange();
  console.log('更新输入框操作调用完成');
  editFlag.value = false;
  emits('close');
}

// 输入框enter操作
async function handleEnterSaveInput() {
  console.log('handleEnterSaveInput');
  inputRef.value.blur();
}

// 输入框内容变化时
async function handleInputChange(): Promise<void> {
  console.log('handleInputChange', localValue.value);
  if (props.localValueFormatter) {
    localValue.value = props.localValueFormatter(localValue.value);
  }
  console.log('handleInputChange after', localValue.value);
  if (localValue.value !== props.modelValue) {
    if (props.updateFn) {
      loading.value = true;
      const result = props.updateFn(localValue.value, props.tableRow);
      if (
        (typeof result === 'object' || typeof result === 'function') &&
        typeof result.then === 'function'
      ) {
        console.log('执行更新方法; 入参：', localValue.value);
        try {
          const res = await result;
          console.log('执行更新方法成功', res);
          emits('update:modelValue', localValue.value);
          emits('change');
          loading.value = false;
          return Promise.resolve();
        } catch (error) {
          console.log('执行更新方法失败', error);
          localValue.value = props.modelValue;
          loading.value = false;
          return Promise.resolve();
        }
      } else {
        console.log('handleInputChange updateFn方法返回的不是Promise');
        localValue.value = props.modelValue;
        loading.value = false;
        return Promise.resolve();
      }
    } else {
      console.log('handleInputChange 值变化，但没有updateFn函数');
      emits('update:modelValue', localValue.value);
      emits('change');
      return Promise.resolve();
    }
  }
  console.log('handleInputChange 值无变化');
  return Promise.resolve();
}

/**
 * 关闭编辑框
 */
function handleCloseInput() {
  console.log('handleCloseInput');
  editFlag.value = false;
  localValue.value = props.modelValue;
}

/**
 * 初始化操作
 */
function init() {
  // 如果一直显示input，将localValue赋初值
  if (props.alwaysInput) {
    localValue.value = props.modelValue;
  }
}

init();

defineExpose({
  handleCloseInput
});
</script>
<style lang="scss" scoped>
// 盘查的表格填写样式（与足迹略有差异）
.c-table-edit-cell-wrapper {
  position: static !important;
  &:focus-within {
    .c-table-edit-cell-input {
      background: #ffffff;
    }
  }

  .c-table-edit-cell-text {
    position: absolute;
    top: 0;
    left: 0;
    width: calc(100% - 1px);
    height: calc(100% - 1px);
    padding: 12px 16px;
    line-height: 20px;
    display: flex;
    align-items: center;
    &.c-table-edit-cell-text--left {
      text-align: left;
      padding-right: 16px;
      justify-content: flex-start;
    }
    &.c-table-edit-cell-text--right {
      text-align: right;
      padding-left: 16px;
      justify-content: flex-end;
    }
    .c-table-edit-cell-text--placeholder {
      color: #ced4da !important;
    }
  }
  .c-table-edit-cell-icon-wrapper {
    z-index: 2;
    top: 0;
    position: absolute;
    display: flex;
    align-items: center;
    height: 100%;
    &.c-table-edit-cell-icon-wrapper--hide {
      display: none;
    }
    &.c-table-edit-cell-icon-wrapper--left {
      right: 12px;
    }
    &.c-table-edit-cell-icon-wrapper--right {
      left: 12px;
    }
    .c-table-edit-cell-icon {
      color: #96a7b3;
      font-size: 12px;
      &:hover {
        color: #03ac82;
      }
    }
  }

  .c-table-edit-cell-input {
    top: 0;
    left: 0;
    z-index: 2;
    position: absolute;
    outline: none;
    border: 0;
    width: calc(100% - 1px);
    height: calc(100% - 1px);
    padding: 0 16px;
    box-sizing: border-box;
    &.c-table-edit-cell-input--left {
      text-align: left;
      padding: 0 26px 0 16px;
    }
    &.c-table-edit-cell-input--right {
      text-align: right;
      padding: 0 16px 0 26px;
    }
    &.c-table-edit-cell-input--active {
      top: -1px;
      left: -1px;
      width: calc(100% + 1px);
      height: calc(100% + 1px);
      border: 1px solid #028968;
      z-index: 4;
    }
    &.c-table-edit-cell-input--error {
      top: -1px;
      left: -1px;
      width: calc(100% + 1px);
      height: calc(100% + 1px);
      border: 1px solid red;
      z-index: 3;
    }
  }

  input::-webkit-input-placeholder {
    color: #ced4da !important;
  }

  input:-moz-placeholder {
    color: #ced4da !important;
  }

  input::-moz-placeholder {
    color: #ced4da !important;
  }

  input:-ms-input-placeholder {
    color: #ced4da !important;
  }

  input::-ms-input-placeholder {
    color: #ced4da !important;
  }

  input::placeholder {
    color: #ced4da !important;
  }
}

/* 
 * 行hover的样式
 * element-plus是hover-row
 * vxe-table是row--hover
*/
.hover-row,
.row--hover {
  .table-row .c-table-edit-cell-icon-wrapper {
    display: flex;
  }
}

.table-cell:hover {
  .c-table-edit-cell-icon-wrapper {
    display: flex;
  }
}
</style>
<style lang="scss">
.vxe-table--body {
  .vxe-body--row {
    // 有且仅有一行的情况
    &:first-child:last-child {
      .c-table-edit-cell-input {
        top: 0 !important;
      }
      .c-table-edit-cell-input--active,
      .c-table-edit-cell-input--error {
        height: calc(100% - 1px) !important;
      }
    }
    &:first-child:not(&:last-child) {
      .c-table-edit-cell-input {
        top: 0 !important;
        height: 100% !important;
        border-bottom: 1px solid #ebeff2;
      }
      // 激活状态底边为绿色
      .c-table-edit-cell-input--active {
        border-bottom-color: #028968;
      }
      // 错误状态底边为红色
      .c-table-edit-cell-input--error {
        border-bottom-color: red;
      }
    }
    &:last-child:not(&:first-child) {
      .c-table-edit-cell-input {
        height: calc(100% - 2px) !important;
      }
      .c-table-edit-cell-input--active,
      .c-table-edit-cell-input--error {
        height: 100% !important;
      }
    }
  }
}
</style>
